
#include "Lexer.h"

using namespace ttg_internal;

//-------------
//--- Lexer ---
//-------------

Lexer::Lexer(FILE *source)
{
	this->source = source;
	this->state = STATE_PARSING_SECTION;
}

int Lexer::spendSplitters()
{
	int c;
	while ((c = fgetc(source)) == ' ' || c == '\n');
	return c;
}

int Lexer::readNext_Section()
{
	value.clear();
	tag.clear();
	extag.clear();
	int c = spendSplitters();
	//reading potential value;
	while (c != '<' && c != EOF)
	{
		if (c != 9 && c != '\n')
			value.addChar(c);
		else
			value.addChar(' ');
		c = fgetc(source);
	}
	if (c == EOF)
		return type = XML_END_OF_FILE;
	//reading tag
	switch (c = fgetc(source))
	{
		case '?': while ((c = fgetc(source)) != '?' && c != EOF)
					  tag.addChar(c);
				  if (c == EOF || (c = fgetc(source)) != '>')
					  return type = XML_ERROR;
				  return type = XML_TAG_INF; break;

		case '!': if ((c = fgetc(source)) != '-' || (c = fgetc(source)) != '-')
					  return type = XML_ERROR;
				  while (true)
				  {
					  while ((c = fgetc(source)) != '-' && c != EOF)
						  tag.addChar(c);
					  if (c == EOF)
						  return type = XML_ERROR;
					  if ((c = fgetc(source)) != '-')
					  {
						  tag.addChar('-');
						  tag.addChar(c);
					  }else
					  if ((c = fgetc(source)) != '>')
					  {
						  tag.addString("--");
						  tag.addChar(c);
					  }
					  else
						  return type = XML_TAG_COMMENT;
				  } break;

		case '/': while ((c = fgetc(source)) != '>' && c != EOF)
					  tag.addChar(c);
				  if (c == EOF)
					 return type = XML_ERROR;
				  return type = XML_TAG_CLOSE; break;

		default:  tag.addChar(c);
				  while ((c = fgetc(source)) != '>' && c != ' ' && c != '\n' && c != EOF)
					  tag.addChar(c);
				  if (c == EOF)
					 return type = XML_ERROR; else
				  if (c == ' ' || c == '\n')
				  {
					  state = STATE_PARSING_TAG;
					  extag.addString(tag.showContent());
				  }
				  return type = XML_TAG_OPEN; break;
	}
	return type = XML_ERROR;
}

int Lexer::readNext_Tag()
{
	tag.clear();
	value.clear();
	int c = spendSplitters();
	if (c == EOF)
		return type = XML_ERROR;
	switch (c)
	{
		case '>': state = STATE_PARSING_SECTION;
				  return readNext_Section();
		
		case '/': if ((c = fgetc(source)) != '>')
					  return type = XML_ERROR;
				  tag.addString(extag.showContent());
				  state = STATE_PARSING_SECTION;
				  return type = XML_TAG_CLOSE;

		case '"': if (attr.isEmpty())
					   return type = XML_ERROR;
				   while ((c = fgetc(source)) != '"' && c != EOF)
					   if (c != 9 && c != '\n')
							value.addChar(c);
					   else
						    value.addChar(' ');
				   if (c == EOF)
					   return type = XML_ERROR;
				   tag.addString(attr.showContent());
				   attr.clear();
				   return type = XML_TAG_CLOSE;

		default:  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
				  {
					  while (c != EOF && c != '=' && c != ' ' && c != '\n')
					  {
						  attr.addChar(c);
						  c = fgetc(source);
					  }
					  if (c == ' ' || c == '\n')
						  c = spendSplitters();
					  if (c != '=')
						  return type = XML_ERROR;
					  tag.addString(attr.showContent());
					  return type = XML_TAG_OPEN;
				  }
				  else
					  return type = XML_ERROR;
	}
}

int Lexer::readNext()
{
	if (state == STATE_PARSING_SECTION)
		return readNext_Section();
	else
		return readNext_Tag();
}

int Lexer::getType() const
{
	return type;
}

const char *Lexer::showTag() const
{
	return tag.showContent();
}

const char *Lexer::showValue() const
{
	return value.showContent();
}

void Lexer::addTag(int tag, const char *name)
{
	switch (tag)
	{
		case XML_TAG_OPEN:
			fprintf(source, "%s<%s>\n", attr.showContent(), name);
			attr.addChar(9);
			break;
		case XML_TAG_CLOSE:
			attr.removeChar();
			fprintf(source, "%s</%s>\n", attr.showContent(), name);
			break;
		case XML_TAG_COMMENT:
			fprintf(source, "%s<!-- %s -->\n", attr.showContent(), name);
			break;
		case XML_TAG_INF:
			throw ttg::Error(ttg::Error::LOCAL, "Lexer", "addTag", "Not implemented yet");
		case XML_END_OF_FILE:
			throw ttg::Error(ttg::Error::LOCAL, "Lexer", "addTag", "Not implemented yet");
		default:
			throw ttg::Error(ttg::Error::LOCAL, "Lexer", "addTag", "Unknown tag");
	}
}

void Lexer::addValue(const char *val)
{
	fprintf(source, "%s%s\n", attr.showContent(), val);
}

FILE *Lexer::getSource()
{
	return source;
}

Lexer::~Lexer()
{
	if (source != NULL)
		fclose(source);
}
